package team02.client;

import static com.google.gwt.query.client.GQuery.$;

import java.util.ArrayList;

import team02.client.core.test.Test;
import team02.client.core.test.question.Question;
import team02.client.core.test.question.QuestionS;
import team02.client.core.test.question.QuestionWR;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONBoolean;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class Demo implements EntryPoint {

	private TestServiceAsync testServiceAsync = GWT.create(TestService.class);
	private Test test;
	public int currentQuestion;

	@Override
	public void onModuleLoad() {
		
		exportStaticMethod(this);
		//		exportStopWatchFunction(new StopWatch());
		init();
	}

	private native void init() /*-{
		$wnd.init();
	}-*/;

	public static native void displayTestInfo(String title, String subtitle, String startTime, String endTime,
			String type)/*-{
		$wnd.test.displayTestInfo(title, subtitle, startTime, endTime, type);
	}-*/;

	public native void exportStaticMethod(Demo demo) /*-{
		var loader = demo;
		$wnd.gwt = {};
		$wnd.gwt.greeting = $entry(@team02.client.Demo::greeting(Ljava/lang/String;));
		$wnd.gwt.loadTest = function(){
			loader.@team02.client.Demo::loadTest()();
		};
		$wnd.gwt.viewScore = function(){
			loader.@team02.client.Demo::viewScore()();
		};
		$wnd.gwt.gotoQuestion = function(number){
			return loader.@team02.client.Demo::gotoQuestion(I)(number);
		};
		$wnd.gwt.getCurrentQuestion = function(){
			return loader.@team02.client.Demo::currentQuestion;
		};
		$wnd.gwt.setUsedTime = function(number, time){
			loader.@team02.client.Demo::setUsedTime(II)(number, time);
		};
		$wnd.gwt.isFixed = function(){
			return loader.@team02.client.Demo::test.@team02.client.core.test.Test::getType()()
			 == @team02.client.core.test.Test::TYPE_FIX;
		};
		$wnd.gwt.storeSelected = function(questionNo, selected){
			(loader.@team02.client.Demo::test.@team02.client.core.test.Test::get(I)(questionNo - 1))
			.@team02.client.core.test.question.Question::setExamineeSelection(Lcom/google/gwt/core/client/JsArrayInteger;)(selected);
		};
		
		$wnd.gwt.storeWrite = function(questionNo, write){
			(loader.@team02.client.Demo::test.@team02.client.core.test.Test::get(I)(questionNo - 1))
			.@team02.client.core.test.question.Question::setExamineeWrite(Lcom/google/gwt/core/client/JsArrayString;)(write);
		};
		
		$wnd.gwt.setSubmit = function(questionNo, submitted){
			(loader.@team02.client.Demo::test.@team02.client.core.test.Test::get(I)(questionNo - 1))
			.@team02.client.core.test.question.Question::setSubmitted(Z)(submitted);
		};
		$wnd.gwt.submitAll = function(){
			loader.@team02.client.Demo::submitAll()();
		};
		$wnd.gwt.getLastQuestion = function(){
			return loader.@team02.client.Demo::test.@team02.client.core.test.Test::size()();
		};
	}-*/;

	public void viewScore() {
		int examineeId = 0;
		try {
			examineeId = Integer.valueOf($("#examinee_id").html());
		} catch (Exception e) {
			// TODO: handle exception
		}
		if(examineeId > 0) {
			// Initialize the service proxy.
			if (testServiceAsync == null) {
				testServiceAsync = GWT.create(TestService.class);
			}

			// Make the call to the stock price service.
			testServiceAsync.viewScore(examineeId, new AsyncCallback<String>() {

				@Override
				public void onFailure(Throwable caught) {
					Window.alert(caught.getMessage());
				}

				@Override
				public void onSuccess(String result) {
					if(result == null) onFailure(new NullPointerException("Result Null"));
					displayScore(result);
				}
			});
		}
	}
	
	protected native void displayScore(String result) /*-{
		$wnd.test.displayScore(result);
	}-*/;

	public void loadTest() {
		currentQuestion = 0;
		int userId = 0;
		long time = 0;
		try {

			userId = Integer.valueOf($("#created_by").html());
			time = Long.valueOf($("#created_time").html());
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (userId > 0 && time > 0) {
			loadTest0(userId, time);
		} 

	}
	
	public void submitAll() {
		test.get(currentQuestion - 1).setSubmitted(true);
		// Initialize the service proxy.
		if (testServiceAsync == null) {
			testServiceAsync = GWT.create(TestService.class);
		}

		// Make the call to the stock price service.
		testServiceAsync.submitTest(this.test, new AsyncCallback<Void>() {

			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				logout();
			}

			@Override
			public void onSuccess(Void result) {
				Window.alert("試験は終わりました");
				logout();
			}});
	}

	protected native void logout()/*-{
		$wnd.test.redirect('logout.t02');
	}-*/;

	public void setUsedTime(int questionNumber, int usedTime) {
		if (questionNumber < 1) return;
		this.test.get(questionNumber - 1).setUsedTime(Long.valueOf(usedTime));
	}

	private int gotoQuestion(int number) {
		if (number < 1 || number > this.test.size()) return 1;
		if (number == currentQuestion) return 0;
		if (test.getType().equals(Test.TYPE_FIX) && number != currentQuestion + 1) {

			return 2;
		} else {
			Question q = test.get(number - 1); //zero based
			if (q.getType().equals(Question.TYPE_SELECTION)) {
				JSONObject selections = new JSONObject();
				ArrayList<QuestionS> selectionList = q.getSelectionList();
				//				Map<Integer, String> selections = new HashMap<Integer, String>(selectionList.size());
				for (QuestionS questionS : selectionList) {
					boolean selected = q.getExamineeSelection().contains(questionS.getSelectionNumber());
					JSONArray content = new JSONArray();
					content.set(0, new JSONString(questionS.getContent()));
					content.set(1, JSONBoolean.getInstance(selected));
					selections.put(String.valueOf(questionS.getSelectionNumber()), content);
				}
				displayQuestionS(number, q.getContent(), selections, String.valueOf(q.getTimeOutDuration()));
			} else {
				JSONObject writes = new JSONObject();
				ArrayList<QuestionWR> writeList = q.getWriteList();
				//				Map<Integer, Integer> writes = new HashMap<Integer, Integer>(writeList.size());
				for (QuestionWR questionWR : writeList) {
					questionWR.getMaxChar();
					JSONArray content = new JSONArray();
					content.set(0, new JSONNumber(questionWR.getMaxChar()));
					content.set(1, new JSONString(q.getExamineeWrite().get(questionWR.getWriteNumber() - 1)));
					writes.put(String.valueOf(questionWR.getWriteNumber()), content);
				}
				displayQuestionWR(number, q.getContent(), writes, String.valueOf(q.getTimeOutDuration()));
			}
			currentQuestion = number;
			return 0;
		}
	}

	private native void displayQuestionWR(int number, String content, JSONObject writes, String limitTime)/*-{
		$wnd.test.displayQuestionWR(number, content, writes, limitTime);
	}-*/;

	private native void displayQuestionS(int number, String content, JSONObject selections, String limitTime)/*-{
		$wnd.test.displayQuestionS(number, content, selections, limitTime);
	}-*/;

	private void loadTest0(int id, long time) {
		// Initialize the service proxy.
		if (testServiceAsync == null) {
			testServiceAsync = GWT.create(TestService.class);
		}

		// Make the call to the stock price service.
		testServiceAsync.getTest(id, time, new AsyncCallback<Test>() {

			@Override
			public void onFailure(Throwable caught) {
				caught.printStackTrace(System.out);
				Window.alert(caught.getMessage());
			}

			@Override
			public void onSuccess(Test test) {
				if (test == null) {
					onFailure(new NullPointerException("Test not found"));
					return;
				}
				display(test);
			}
		});
	}
//
//	private void loadTest(String content) {
//		// Initialize the service proxy.
//		if (testServiceAsync == null) {
//			testServiceAsync = GWT.create(TestService.class);
//		}
//
//		// Make the call to the stock price service.
//		testServiceAsync.getTest(content, new AsyncCallback<Test>() {
//
//			@Override
//			public void onFailure(Throwable caught) {
//				caught.printStackTrace(System.out);
//				Window.alert(caught.getMessage());
//			}
//
//			@Override
//			public void onSuccess(Test test) {
//				if (test == null) {
//					onFailure(new NullPointerException("Test not found"));
//					return;
//				}
//				display(test);
//			}
//		});
//	}

	protected void display(Test test) {
		this.test = test;
		displayTestInfo(test.getTitle(), test.getSubtitle(), String.valueOf(test.getStartTime()),
				String.valueOf(test.getEndTime()), test.getType());
	}

	public static void greeting(String message) {
		Window.alert(message);
	}
}
